Limiting the number of active builder is documented and possible using Interlocks.
While this is working well, there is a slight disadvantage because the slave is assigned and busy waiting for the lock to be available.
There is a simple solution by using custom nextBuild function. The following example is equivalent to using a buildbot master lock:
def myNextBuild(bldr, requests): if len(bldr.building): return None return requests