That passing of the binding around, I would argue, is a GOOD thing. It makes it very clear that this is a variable that needs special handling. It's not that hard and adds virutally no overhead.
As for what we do when you need lifecycle handling? You do exactly what you've done in this article, you register a lifecycle observer.
I used to use an auto clearing binding similar to what you have with a delegate. I stopped because there are several cases where your solution will fall apart. The most common one that I've run into is the callback from a ListAdapter's submitList call.
eg. adapter.submitList(aList) { binding.setText(...) }
That submitList callback can happen at any time, even after your delegate has rendered the binding invalid, hitting your IllegalState exception. That's one case, but it's not the only. Add coroutines to the mix just makes it more complex.
If you don't use the delegate approach and just keep it as a local variable it forces you to recognize that the binding needs special handling because it is coupled to the lifecycle. Attempting to delegate that handling out just gives you a false sense of security. It hides the fact that you need to be very aware of how a binding it used and it remove the ability for you to better control how and when it's accessed.
The cost of not using the delegate? Passing the binding along in function params and registering lifecycle observers. That's it. It's virtually nothing.