The DrainComplete() caught with mWaitForInternalDrain still won't necessarily be from the internal Drain(), but all we need is that one DrainComplete() is caught for the internal Drain() because one more will be generated if there is a Drain() in progress.
What protecting mWaitForInternalDrain access with the monitor provides here is that the compiler won't use its address for storage of other data meaningless in the context of mWaitForInternalDrain and so, for example, two DrainComplete() calls won't unintentionally think that they are both for one internal drain.