Having abstract inputs and concrete outputs makes your function more general. This means it can be used in more ways. On the other hand it puts stronger constraints of your method, limiting how future implementations of it might work. So it's a trade-off between different goals.

It could be you heard an extrapolation of Postel's law: "Be conservative in what you send, liberal in what you accept."

Mostly it's about maximizing code reusability. It's easy to come up with cases to demonstrate why it helps. Consider Java's Iterable<T> as an example. If the only thing your method does is iterate through all the Ts, having an Iterable<T> as your parameter type allows you to use that method with over 60 built-in classes, not to mention any custom classes that implement the interface. If you limited it to, say, Vector<T>, then any code that calls your method would have to convert to a Vector<T> first.

On the other hand, returning an Iterable<T> from a method limits the amount of code that can use your return value to those that take an Iterable<T> parameter. If you return a very concrete type, like Vector<T>, then your return value can be passed into any method that takes a Serializable, Cloneable, Iterable<T>, Collection<T>, List<T>, RandomAccess, Vector<T>, AbstractList<T>, or AbstractCollection<T>, and it will work as expected.