Basically, you include some sort of version mechanism (generally with more granularity than just low/high version limits), and you try to keep interfaces separate and "orthogonal". But a lot depends on which side of the interface you're on. On the "consumer" side you can only do so much.
IBM System/38 and it's descendents managed to maintain compatibility such that programs compiled on the first release could still be run, without recompiling, 30 years later (and through two revisions of the machine instruction set, the second quite drastic). But that is an unusual case of pretty good (though not perfect) original design, combined with fairly strong motivation (large banks that spend a lot of $$ on the systems) to maintain compatibility.
At the personal computer level many system designers don't really care, since incompatibility sells more software upgrades, which in turn sells more hardware.