removing inout from port arrays
The simplest solution is split output and input for the driver modules.

module driver0 #(paramerter N=8)(input [N-1:0] sig_in, output sig_out);
    assign sig_out = 'b1;  // drive with some real value
endmodule

module driver1 #(paramerter N=8)(input [N-1:0] sig_in, output sig_out);
    assign sig_out = 'b1;  // drive with some real value
endmodule


You can allow the output to also be an input of the same module in top

module top();
    paramerter N=8;
    wire [N-1:0] sig;
    driver0 #(N) u0(.sig_in(sig), .sig_out(sig[0]));
    driver1 #(N) u1(.sig_in(sig), .sig_out(sig[1]));
endmodule


Or you can prevent the driver's output to feedback by slicking the array for the input. This may take a bit more caution. You could partition the inputs signals as two or more as well. Which ever is more intuitive easier manage for the project.

module top();
    paramerter N=8;
    wire [N-1:0] sig;
    driver0 #(N-1) u0(.sig_in(sig[N-1:1]), .sig_out(sig[0]));
    driver1 #(N-1) u1(.sig_in({sig[N-1:2],sig[0]}), .sig_out(sig[1]));
endmodule


Since IEEE Std 1364-2001, Verilog allows some fancy port definitions. See IEEE Std 1364-2001 &sect; 12.3.3 Port declarations or SystemVerilog's IEEE Std 1800-2012 &sect; 23.2.2 Port declarations
Support for this may very across tools as this practices is not common. If your synthesizer has issues with interface it may have issues with port aliasing as well. 

module driver0 ( .sig({sig_in,sig_out}) );
  input sig_in;
  output sig_out;
  assign sig_out = 'b1;  // drive with some real value
endmodule

module driver1 ( .sig({sig_in,sig_out}) );
  input sig_in;
  output sig_out;
  assign sig_out = 'b1;  // drive with some real value
endmodule

module top();
    wire [1:0] sig;
    driver0 u0(.sig(sig));
    driver1 u1(.sig(sig));
endmodule




If the bus is going across several lays of hierarchy then the above solution will likely be tedious to manage. An interface should be used. Some guidelines to reduce synthesis limitations:


Define all signals as a logic type. Only exception are tri-states where the bits are expected to have two or more drivers.
Define all tri-states as wire or tri
Assign all logic types within a always_ff, always_comb, always_latch (if latch is necessary block. logic types can be assigned with assign statements, but not all tools validate driving conflicts with assign
Keep tri-states assignments as simple of possible


Ex: assign myif.io = drive_enable ? io_out : 'z;

Do not use interface as a port in the top most module that will be synthesized. Many current synthesizers will flatten and localize interfaces with escaped names. If needed, create wrapper module as a translation layer between interface and top most port signals. Ex:

interface my_interface(input clk, 
    /*May need to declare top port level tri-stats as an interface port*/
    inout [7:0] io, ...
    /*Optional output logic ... , input ... */ );
  logic in_a, in_b, out;
  //wire [7:0] io; // internal tri-state
  ...
endinterface : my_interface
module same_port #(parameter N=1) (a,a); // Synthesizer might support this, see manual
  inout [N-1:0] a;
endmodule : same_port
...
// RTL top with interface as port
module my_top(my_interface myif);
  ...
  sub sub0 ( .myif(myif), .*);
  ...
endmodule : my_top
// wrapper to use for synthesis
module synth_top( output logic out, input in_a, in_b, clk, inout [7:0] io, ...);
  my_interface myif( .* );
  my_top mytop( .myif(myif) );

  // connect myif sigs with port sigs thate are not already connected with .*
  always_comb begin : conn_in
    myif.in_a = in_a;
    myif.in_b = in_b;
    ...
  end : conn_in
  always_comb begin : conn_out
    out = myif.out;
    ...
  end : conn_out
  /* connect tri-state this way may not be supported by all synthesizers,
   * refer to manual */
  //same_port #(8) conn_inout_io(io, myif.io); 
  ...
endmodule : synth_top