First, understand that a purely abstract class is really just an interface that can't do multiple inheritance.
Write class, extract interface, is a brain dead activity. So much so that we have a refactoring for it. Which is a pity. Following this "every class gets an interface" pattern not only produces clutter it completely misses the point.
An interface should not be thought of as simply a formal restatement of whatever the class can do. An interface should be thought of as a contract imposed by the using client code detailing it's needs.
I have no trouble at all writing an interface that currently only has one class implementing it. I actually don't care if no class at all implements it yet. Because I'm thinking about what my using code needs. The interface expresses what the using code demands. Whatever comes along later can do what it likes so long as it satisfies these expectations.
Now I don't do this every time one object uses another. I do this when crossing a boundary. I do it when I don't want one object to know exactly which other object it's talking to. Which is the only way polymorphism will work. I do it when I expect the object my client code is talking to be likely to change. I certainly don't do this when what I'm using is the String class. The String class is nice and stable and I feel no need to guard against it changing on me.
When you decide to interact directly with a concrete implementation rather then through an abstraction you're predicting that the implementation is stable enough to trust not to change.
That right there is the way I temper the Dependency Inversion Principle. You shouldn't blindly fanatically apply this to everything. When you add an abstraction you're really saying you don't trust the choice of implementing class to be stable over the life of the project.
This all assumes you're trying to follow the Open Closed Principle. This principle is important only when the costs associated with making direct changes to established code are significant. One of the main reasons people disagree on how important decoupling objects is because not everyone experiences the same costs when making direct changes. If retesting, recompiling, and redistributing your entire code base is trivial to you then resolving a need for change with direct modification is likely a very attractive simplification of this problem.
There simply isn't a brain dead answer to this question. An interface or abstract class isn't something you should add to every class and you can't just count the number of implementing classes and decide it's not needed. It's about dealing with change. Which means you're anticipating the future. Don't be surprised if you get it wrong. Keep it simple as you can without backing yourself into a corner.
So please, don't write abstractions just to help us read the code. We have tools for that. Use abstractions to decouple what needs decoupling.