The summary of the answer is that you can pass the size of the array when and only when the array is a dummy argument in the subprogram.
From the standard:
Each array declarator is either an actual array declarator or a dummy array declarator.
5.1.2.1 Actual Array Declarator.
An actual array declarator is an array declarator in which the array name is not a dummy argument. Each actual array declarator must be a constant array declarator. An actual array declarator is permitted in a [..] COMMON statement5.1.2.2 Dummy Array Declarator.
A dummy array declarator is an array declarator in which the array name is a dummy argument. A dummy array declarator may be [..] an adjustable array declarator [..]. A dummy array declarator may appear only in a function or subroutine subprogram.
If you want to pass arrays in a common block then you'll need to have the bounds as an integer constant expression. As you say, you can define the array size again in the subprogram. Using a source pre-processor could be one way to help keep things consistent. Or, as @george suggests, using a standard-friendly include
statement (just make sure you're using a build system).
That said, I suggest it's better to pass arrays as arguments: when you want to use "dynamic" array approaches things will be tricky enough without having to worry about storage association.