Why couldn't you have more than one instance of a 16-bit multi-DS program?
Recall that the HINSTANCE identified a set of variables.
This causes a bit of a problem if your program has multiple data
segments; in other words, multiple sets of variables.
In such a program,
the code would load the data segment of whatever variable it needed
each time it needed to access a variable from a different segment.
This was no problem at all for a DLL,
since 16-bit DLLs were single-instance.
Go ahead, load your selectors whenever you want.
Since there's only one copy of each data segment,
you can just use them in your code and let the loader fix them up.
No matter which processes calls your DLL, you're still good.
But if you are doing this in a program,
you run into trouble once the user runs a second copy of the
program.
All you get is an HINSTANCE
to pass to MakeProcInstance
(or to infer from your stack selector).
In other words, you get one set of variables.
If your program uses multiple sets of variables,
you don't have a way to access those other variables,
and the operating system has no way of telling you where
they are.
Now, a sufficiently clever compiler could work around this
failure of mathematics.
It could store the selectors of the extra data segments
into the data segment specified by the HINSTANCE.
When the program needed to access a variable from another
data segment, it could access them by loading the appropriate
selector from the stack segment register
(since SS == DS).
I don't know whether anybody actually bothered to write
a compiler that did this.
Not that writing one today will win you any accolades
since nobody writes 16-bit Windows programs any more.
It's one of those things that may have been a neat idea back
in its day but today will just get you quizzical looks.
Think of it as the computer version of inventing a
higher-capacity eight-track cartridge.