It's been over a year now but no correct answers were given so here's my take on it.
Let's start with the type signature:
tails' :: [a] -> [[a]]
This sugests that tails' should return a list-of-lists. The terminal case you syggested is just an empty list. Change it to:
tails' [] = [[]]
Now, the general case. Let's assume that our tails' works the way we want it to:
tails' []      -> [[]]
tails' [1]     -> [[1], []]
tails' [2,1]   -> [[2,1], [1], []]
tails' [3,2,1] -> [[3,2,1], [2,1], [1], []]
As we can see, we want to include the original list and the empty list. This means that given an input list xs, we want to concatenate xs onto something else.
But what's that something else? Let's do a bit of pseudo-haskell math:
let A = tails' [3,2,1] = [[3,2,1], [2,1], [1], []]
let B = tails' [2,1] = [[2,1], [1], []]
=> A = [[3,2,1], B] -- (1)
tail [3,2,1] == [2,1]
=> B = tails' (tail [3,2,1]) -- (2)
By (1) and (2)
A = [[3,2,1], tails' (tail [3,2,1])]
=> tails' [3,2,1] = [[3,2,1], tails' (tail [3,2,1])] -- (3)
By replacing [3,2,1] in (3) with xs
tails' xs = [xs, tails' (tail xs)]
Translating all this into Haskell gives us:
tails' :: [a] -> [[a]]
tails' [] = [[]]
tails' xs = xs : (tails' $ tail xs)
main = do
  print $ tails' [1,2,3]
-- [[1,2,3],[2,3],[3],[]]