I would like to believe that "break"-as-a-expression solves most of these issues. It is reasonable, though, to drop the "return"-as-an-expression part of the proposal, because you need to know that the comprehension is run in a separate function to understand it (it's a bit ironic that I am dropping the original proposal to defend my own, now...).
((x, y) for x in l1 if f1(x) or break for y in l2 if f2(y) or break)
This maps directly to
for x in l1:
if f1(x) or break:
for y in l2:
if f2(y) or break:
yield x, y
which is literally a copy-paste of the second part followed by yielding the first part. I think this reads reasonably well but this is obviously a subjective issue.