I think I've figured out how to do it. (Not neatly, though.)
Here's a 3-of-5 pay to multi-pubkeyhash:
scriptSig: <key1> <key2> <key3> <sig1> <sig2> <sig3> <pos1> <pos2> <pos3>
scriptPubKey: <hash1> <hash2> <hash3> <hash4> <hash5>
// key1
// get the key <key1> and hash it
+2 13 OP_PICK OP_DUP OP_HASH160
// copy pos1
+1 9 OP_PICK
// check 2 < pos1 < 7
+0 OP_DUP 2 7 OP_WITHIN OP_VERIFY
// copy to alt stack
+0 OP_DUP OP_TOALTSTACK
// get hash at pos1
-2 OP_PICK OP_EQUALVERIFY
// check signature
-1 11 OP_PICK OP_SWAP OP_CHECKSIGVERIFY
// key2
// get the key <key2> and hash it
+2 12 OP_PICK OP_DUP OP_HASH160
// copy pos2
+1 8 OP_PICK
// check 2 < pos2 < 7
+0 OP_DUP 2 7 OP_WITHIN OP_VERIFY
// check pos2 < pos1
+0 OP_DUP OP_FROMALTSTACK OP_LESSTHAN OP_VERIFY
// copy to alt stack
+0 OP_DUP OP_TOALTSTACK
// get hash at pos2
-2 OP_PICK OP_EQUALVERIFY
// check signature
-1 10 OP_PICK OP_SWAP OP_CHECKSIGVERIFY
// key3
// get the key <key3> and hash it
+2 11 OP_PICK OP_DUP OP_HASH160
// copy pos3
+1 7 OP_PICK
// check 2 < pos2 < 7
+0 OP_DUP 2 7 OP_WITHIN OP_VERIFY
// check pos3 < pos2
+0 OP_DUP OP_FROMALTSTACK OP_LESSTHAN OP_VERIFY
// get hash at pos3
-2 OP_PICK OP_EQUALVERIFY
// check signature
+0 9 OP_PICK OP_SWAP OP_CHECKSIG
(The number at the start of each line is how many stack elements that line adds or removes.)
The idea is that the spender provides the keys, the signatures, and the index of the hash that they're signing for. (keyN, sigN, and posN.) To prevent someone from providing the same index three times, we check that pos1 > pos2 > pos3. It's much longer than an equivalent multisig script, but on the plus side we do fewer signature verifications. (Normal 3-of-5 multisig will do up to 5 signature operations, but we only do 3.)
(Standard disclaimer about using untested scripts applies. If I made an off-by-one error above, all your money's gone.)