I believe you do it in the same way as any other asynchronous operation in .NET: you call the BeginXxx version of the method, in this case BeginAcceptSocket. Your callback will execute on the thread pool.
Pooled threads generally scale much better than thread-per-connection: once you get over a few tens of connections, the system works much harder in switching between threads than on getting actual work done. In addition, each thread has its own stack which is typically 1MB in size (though it depends on link flags) which has to be found in the 2GB virtual address space (on 32-bit systems); in practice this limits you to fewer than 1000 threads.
I'm not sure whether .NET's threadpool currently uses it, but Windows has a kernel object called the I/O Completion Port which assists in scalable I/O. You can associate threads with this object, and I/O requests (including accepting incoming connections) can be associated with it. When an I/O completes (e.g. a connection arrives) Windows will release a waiting thread, but only if the number of currently runnable threads (not blocked for some other reason) is less than the configured scalability limit for the completion port. Typically you'd set this to a small multiple of the number of cores.